﻿namespace PageTypeBuilderUI
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using Configuration;
    using CustomProperties;
    using EPiServer.DataAbstraction;
    using EPiServer.Framework;
    using EPiServer.Framework.Initialization;
    using log4net;
    using PageTypeBuilder;
    using PageTypeBuilder.Abstractions;
    using PageTypeBuilder.Discovery;
    using PageTypeBuilder.Reflection;
    using Reflection;

    [ModuleDependency(typeof(PageTypeBuilder.Initializer))]
    public class Initializer : IInitializableModule
    {
        private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        public void Initialize(InitializationEngine context)
        {
            PageTypeBuilderUIConfiguration configuration = PageTypeBuilderUIConfiguration.GetConfiguration();

            if (!configuration.EnablePageTypeUpdating)
                return;

            List<PageTypeDefinition> pageTypes = new PageTypeDefinitionLocator(new AppDomainAssemblyLocator()).GetPageTypeDefinitions().ToList();

            foreach (PageTypeDefinition pageTypeDefinition in pageTypes)
            {
                IPageType pageType = new WrappedPageType(PageType.Load(pageTypeDefinition.Attribute.Name));
                Type pageTypeType = PageTypeResolver.Instance.GetPageTypeType(pageType.ID);

                List<PropertyInfo> propertyGroupProperties = pageTypeType.GetPageTypePropertyGroupProperties()
                    .ToList();

                if (propertyGroupProperties.Count() == 0)
                    continue;

                foreach (PropertyInfo propertyGroupProperty in propertyGroupProperties)
                {
                    PageTypePropertyGroupAttribute propertyGroupAttribute = propertyGroupProperty.GetPropertyAttribute<PageTypePropertyGroupAttribute>();
                    string propertyName = propertyGroupProperty.Name;

                    // if property doesn't already exist create it!
                    PageDefinition pageDefinition = pageType.Definitions
                        .Where(current => string.Equals(current.Name, propertyName + "_Container"))
                        .FirstOrDefault();

                    if (pageDefinition == null && configuration.EnableCustomPropertyGroupRendering)
                    {
                        try
                        {
                            pageDefinition = new PageDefinition();
                            pageDefinition.PageTypeID = pageType.ID;
                            pageDefinition.Name = propertyName + "_Container";
                            pageDefinition.EditCaption = GetEditCaption(propertyGroupAttribute);
                            pageDefinition.LanguageSpecific = true;
                            pageDefinition.DisplayEditUI = true;

                            pageDefinition.Type = PageDefinitionType
                                .List()
                                .Where(current => string.Equals(current.Name, typeof(PropertyGroupProperty).Name))
                                .First();
                            pageDefinition.FieldOrder = propertyGroupAttribute.StartSortOrderFrom;

                            TabDefinition tab = TabDefinition.List().First();

                            if (propertyGroupAttribute.Tab != null)
                            {
                                Tab definedTab = (Tab)Activator.CreateInstance(propertyGroupAttribute.Tab);
                                tab = TabDefinition.Load(definedTab.Name);
                            }
                            pageDefinition.Tab = tab;
                            pageDefinition.Save();
                        }
                        catch (Exception ex)
                        {
                            Logger.Error(ex);
                        }
                    }
                    else if (pageDefinition != null && !configuration.EnableCustomPropertyGroupRendering)
                        pageDefinition.Delete();

                    List<PageTypePropertyDefinition> pageTypePropertyDefinitions = pageType.GetPropertyGroupPropertyDefinitions(propertyGroupProperty)
                        .OrderBy(current => current.PageTypePropertyAttribute.SortOrder)
                        .ToList();

                    // if showing again take visibility from definitions if set, otherwise just set to true
                    foreach (PageTypePropertyDefinition propertyDefinition in pageTypePropertyDefinitions)
                    {
                        pageDefinition = pageType.Definitions
                            .Where(current => string.Equals(current.Name, propertyDefinition.Name))
                            .FirstOrDefault();

                        if (pageDefinition == null)
                            continue;

                        if (configuration.EnableCustomPropertyGroupRendering && pageDefinition.DisplayEditUI)
                        {
                            pageDefinition.DisplayEditUI = false;
                            pageDefinition.Save();    
                        }
                        else if (!configuration.EnableCustomPropertyGroupRendering)
                        {
                            pageDefinition.DisplayEditUI = true;
                            pageDefinition.Save();    
                        }
                    }
                }
            }
        }

        public void Uninitialize(InitializationEngine context)
        {
        }

        public void Preload(string[] parameters)
        {
            throw new NotImplementedException();
        }

        private string GetEditCaption(PageTypePropertyGroupAttribute attribute)
        {
            string editCaption = attribute.EditCaptionPrefix;

            if (editCaption.Contains("-"))
                editCaption = editCaption.Substring(0, editCaption.IndexOf("-")).Trim();

            if (editCaption.Contains(":"))
                editCaption = editCaption.Substring(0, editCaption.IndexOf(":")).Trim();

            return editCaption;
        }
        
    }

}
